/*
 *	This program is free software: you can redistribute it and/or modify
 *	it under the terms of the GNU General Public License as published by
 *	the Free Software Foundation, either version 2 of the License, or
 *	(at your option) any later version.
 *
 *	Copyright (C) 2012-2014 PIVA SOFTWARE (www.pivasoftware.com)
 *		Author: Mohamed Kallel <mohamed.kallel@pivasoftware.com>
 *		Author: Anis Ellouze <anis.ellouze@pivasoftware.com>
 *	Copyright (C) 2011 Luka Perkov <freecwmp@lukaperkov.net>
 */

#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <microxml.h> 
#include <time.h>
#include <json-c/json.h> 
#include "cwmp.h"
#include "backup.h" 
#include "config.h"
#include "log.h"

static bool first_run = true;
#ifdef BACKUP_DATA_IN_CONFIG
static struct uci_context *easycwmp_uci_ctx = NULL;
#endif

struct core_config *config;


static void config_free_local(void) {
	if (config->local) {
		FREE(config->local->ip);
		FREE(config->local->interface);
		FREE(config->local->port);
		FREE(config->local->username);
		FREE(config->local->password);
		FREE(config->local->ubus_socket);
	}
}

extern struct json_object *call_mu(struct json_object *parameter);

static int config_init_local(void)
{
	struct uci_section *s;
	struct uci_element *e1;
	int ret = -1;

	do {
		struct json_object *request = NULL, *result = NULL;

		request = json_object_new_object();
		if(NULL == request)
			break;

		json_object_object_add(request, "method", json_object_new_string("Request"));
		json_object_object_add(request, "submethod", json_object_new_string("GetParameterValues"));
		struct json_object *parameterNames = json_object_new_array();
		if(NULL == parameterNames) {
			json_object_put(request);
			break;
		}
		json_object_object_add(request, "parameterNames", parameterNames);
		json_object_array_add(parameterNames, json_object_new_string("Device.ManagementServer.ConnectionRequestPassword"));
		json_object_array_add(parameterNames, json_object_new_string("Device.ManagementServer.ConnectionRequestUsername"));

		result = call_mu(request);
		json_object_put(request);

		if(!result) {
			break;
		}

		struct json_object *parameterValues = NULL;
		json_object_object_get_ex(result, "parameterValues", &parameterValues);
		if(!parameterValues) {
			break;
		}

		struct json_object *tmp = NULL;
		struct json_object *value = NULL;
		json_object_object_get_ex(parameterValues, "Device.ManagementServer.ConnectionRequestPassword", &tmp);
		DD("parameter URL goted %p\n", tmp);
		if(tmp) {
			json_object_object_get_ex(tmp, "Value", &value);
			if(value) {
				config->local->password = strdup(json_object_get_string(value));
			} else {
				config->local->password = strdup(json_object_get_string(tmp));
			}
		} else {
			config->local->password = strdup("test");
		}

		json_object_object_get_ex(parameterValues, "Device.ManagementServer.ConnectionRequestUsername", &tmp);
		DD("parameter Username goted %p\n", tmp);
		if(tmp) {
			json_object_object_get_ex(tmp, "Value", &value);
			if(value) {
				config->local->username = strdup(json_object_get_string(value));
			} else {
				config->local->username = strdup(json_object_get_string(tmp));
			}
		} else {
			config->local->username = strdup("test");
		}

		json_object_put(result);
		ret = 0;

	} while(false);
	

	config->local->interface = strdup("wan");
	DD("easycwmp.@local[0].interface=%s\n", config->local->interface);

	config->local->port = strdup("8088");
	DD("easycwmp.@local[0].port=%s\n", config->local->port);
				
	config->local->logging_level = 1;
	DD("easycwmp.@local[0].logging_level=%d\n", config->local->logging_level);

	return ret;
}

static void config_free_acs(void) {
	if (config->acs) {
		FREE(config->acs->url);
		FREE(config->acs->username);
		FREE(config->acs->password);
		FREE(config->acs->ssl_cert);
		FREE(config->acs->ssl_cacert);
	}
}

static int config_init_acs(void)
{
	struct tm tm;

	config_free_acs();
	config->acs->periodic_time = -1;

	config->acs->http100continue_disable = false;
	DD("easycwmp.@acs[0].http100continue_disable=%d\n", config->acs->http100continue_disable);
	do {
		struct json_object *request = NULL, *result = NULL;

		request = json_object_new_object();
		if(NULL == request)
			break;

		DD("to init request\n");
	
		json_object_object_add(request, "method", json_object_new_string("Request"));
		json_object_object_add(request, "submethod", json_object_new_string("GetParameterValues"));

		struct json_object *parameterNames = json_object_new_array();
		if(NULL == parameterNames) {
			json_object_put(request);
			break;;
		}
		json_object_object_add(request, "parameterNames", parameterNames);

		DD("to init parameter names\n");

		json_object_array_add(parameterNames, json_object_new_string("Device.ManagementServer.EnableCWMP"));
		json_object_array_add(parameterNames, json_object_new_string("Device.ManagementServer.URL"));
		json_object_array_add(parameterNames, json_object_new_string("Device.ManagementServer.Username"));
		json_object_array_add(parameterNames, json_object_new_string("Device.ManagementServer.Password"));
		json_object_array_add(parameterNames, json_object_new_string("Device.ManagementServer.PeriodicInformEnable"));
		json_object_array_add(parameterNames, json_object_new_string("Device.ManagementServer.PeriodicInformInterval"));
		json_object_array_add(parameterNames, json_object_new_string("Device.ManagementServer.PeriodicInformTime"));

		result = call_mu(request);
		json_object_put(request);

		DD("after call mu\n");

		if(result) {
			struct json_object *parameterValues = NULL;
			json_object_object_get_ex(result, "parameterValues", &parameterValues);
			if(!parameterValues) {
				json_object_put(result);
				return -1;
			}

			DD("parameter values goted\n");


			struct json_object *tmp = NULL;
			struct json_object *value = NULL;
			json_object_object_get_ex(parameterValues, "Device.ManagementServer.URL", &tmp);
			DD("parameter URL goted %p\n", tmp);
			if(tmp) {
				json_object_object_get_ex(tmp, "Value", &value);
				if(value) {
					config->acs->url = strdup(json_object_get_string(value));
				} else {
					config->acs->url = strdup(json_object_get_string(tmp));
				}
			} else {
				config->acs->url = strdup("http://192.168.1.118:8080/openacs/acs");
			}

			json_object_object_get_ex(parameterValues, "Device.ManagementServer.Username", &tmp);
			DD("parameter Username goted %p\n", tmp);
			if(tmp) {
				json_object_object_get_ex(tmp, "Value", &value);
				if(value) {
					config->acs->username = strdup(json_object_get_string(value));
				} else {
					config->acs->username = strdup(json_object_get_string(tmp));
				}
			} else {
				config->acs->username = strdup("test");
			}

			json_object_object_get_ex(parameterValues, "Device.ManagementServer.Password", &tmp);
			DD("parameter Password goted %p\n", tmp);
			if(tmp) {
				json_object_object_get_ex(tmp, "Value", &value);
				if(value) {
					config->acs->password = strdup(json_object_get_string(value));
				} else {
					config->acs->password = strdup(json_object_get_string(tmp));
				}
			} else {
				config->acs->password = strdup("test");
			}

			json_object_object_get_ex(parameterValues, "Device.ManagementServer.PeriodicInformEnable", &tmp);
			if(tmp) {
				const char *vtemp = NULL;
				json_object_object_get_ex(tmp, "Value", &value);
				if(value) {
					vtemp = json_object_get_string(value);
				} else {
					vtemp = json_object_get_string(tmp);
				}
				if(vtemp && vtemp[0] == 't') {
					config->acs->periodic_enable = true;
				} else {
					config->acs->periodic_enable = false;
				}
			} else {
				config->acs->periodic_enable = true;
			}

			json_object_object_get_ex(parameterValues, "Device.ManagementServer.PeriodicInformInterval", &tmp);
			if(tmp) {
				json_object_object_get_ex(tmp, "Value", &value);
				if(value) {
					config->acs->periodic_interval = atoi(json_object_get_string(value));
				} else {
					config->acs->periodic_interval = atoi(json_object_get_string(tmp));
				}
			} else {
				config->acs->periodic_interval = 60;
			}

			DD("PeriodicInformInterval %d PeriodicInformEnable %d\r\n", config->acs->periodic_interval, config->acs->periodic_enable);
			json_object_put(result);
			return 0;
		}
	} while(false);

	config_free_acs();
	config->acs->http100continue_disable = false;
	DD("easycwmp.@acs[0].http100continue_disable=%d\n", config->acs->http100continue_disable);
	config->acs->url = strdup("http://192.168.1.118:8080/openacs/acs");
	DD("easycwmp.@acs[0].url=%s\n", config->acs->url);

	config->acs->username = strdup("test");
	DD("easycwmp.@acs[0].username=%s\n", config->acs->username);

	config->acs->password = strdup("test");
	DD("easycwmp.@acs[0].password=%s\n", config->acs->password);

	config->acs->periodic_enable = true;
	DD("easycwmp.@acs[0].periodic_enable=%d\n", config->acs->periodic_enable);

	config->acs->periodic_interval = 60;
	DD("easycwmp.@acs[0].periodic_interval=%d\n", config->acs->periodic_interval);

#if 0
	config->acs->ssl_cert = strdup(uci_to_option(e)->v.string);
	DD("easycwmp.@acs[0].ssl_cert=%s\n", config->acs->ssl_cert);

	config->acs->ssl_cacert = strdup(uci_to_option(e)->v.string);
	DD("easycwmp.@acs[0].ssl_cacert=%s\n", config->acs->ssl_cacert);

	config->acs->ssl_verify = true;
	DD("easycwmp.@acs[0].ssl_verify=%d\n", config->acs->ssl_verify);
#endif

	return 0;
}

int config_init(void)
{
	if (first_run) {
		config = calloc(1, sizeof(struct core_config));
		if (!config) goto error;

		config->acs = calloc(1, sizeof(struct acs));
		if (!config->acs) goto error;

		config->local = calloc(1, sizeof(struct local));
		if (!config->local) goto error;
	}

	return 0;

error:
	return -1;
}


void config_exit(void)
{
	if (config) {
		config_free_acs();
		FREE(config->acs);
		config_free_local();
		FREE(config->local);
		FREE(config);
	}
}

void config_load(void)
{

	config_init();

	if (config_init_local()) goto error;
	if (config_init_acs()) goto error;

	backup_check_acs_url();
	cwmp_periodic_inform_init();

	first_run = false;

	cwmp_update_value_change();
	return;

error:
	log_message(NAME, L_CRIT, "configuration (re)loading failed, exit daemon\n");
	D("configuration (re)loading failed\n"); 
	exit(EXIT_FAILURE);
}

#ifdef BACKUP_DATA_IN_CONFIG
int easycwmp_uci_init(void)
{
	return 0;
}

int easycwmp_uci_fini(void)
{
	return 0;
}

static bool easycwmp_uci_validate_section(const char *str)
{
	return true;
}

int easycwmp_uci_init_ptr(struct uci_context *ctx, struct uci_ptr *ptr, char *package, char *section, char *option, char *value)
{
	return -1;
}

char *easycwmp_uci_get_value(char *package, char *section, char *option)
{
	struct uci_ptr ptr;
	char *val = "";

	return val;
}

char *easycwmp_uci_set_value(char *package, char *section, char *option, char *value)
{
	return "";
}

int easycwmp_uci_commit(void)
{
	return 0;
}
#endif
